module mem_tb;

initial begin
    $dumpfile("mem_tb.vcd"); //生成的vcd文件名称
    $dumpvars(0, mem_tb);    //tb模块名称
    $timeformat(-9, 2, "ns", 4);
end  

localparam TCLK = 20;

reg clk;
reg rst_n;

initial begin
    #0 clk = 0;
    forever
        #(TCLK / 2) clk = ~clk;
end

initial begin
    #0 rst_n = 0;
    #20 rst_n = 1;
end

reg [31:0]  HADDR;
reg [31:0]  HWDATA;
reg         HWRITE;
reg [2:0]   HSIZE;
reg [2:0]   HBURST;
reg         HSEL;
reg [1:0]   HTRANS;
reg         HREADY_IN;

wire         HREADY_OUT;
wire [31:0]  HRDATA;
wire [1:0]   HRESP;

reg print_mem;

initial begin
    HADDR = 32'b0;
    HWRITE = 1'b0;
    HWDATA = 32'b0;

    HSIZE = 3'b0;
    HBURST = 3'b0;
    HSEL = 1'b0;
    HTRANS = 2'b00;
    HREADY_IN = 1'b1;
end

task ahb_read;
    input [31:0] addr;
    output integer value;
    begin
        @(posedge clk);

        HSEL = 1'b1;
        HTRANS = 2'b10;
        HADDR = addr;
        HWRITE = 1'b0;
        HWDATA = {32{1'bx}};
        HSIZE = 3'b010;

        @(posedge clk);

        HTRANS = 2'b00;

        repeat(4) begin
            @(posedge clk);
            if(HREADY_OUT) begin
                // $display("[%m]#%t INFO: Read Value: 0x%08x @ 0x%08x", $time, HRDATA, HADDR);
                value = HRDATA;
                HSEL = 1'b0;
                HADDR = 8'h0;
                HWRITE = 1'b0;
                HWDATA = {32{1'bx}};
                HSIZE = 3'b000;

                HTRANS = 2'b0;
                disable ahb_read;
            end
        end
        $stop;
    end
endtask

task ahb_write;
    input [31:0] addr;
    input integer data;
    begin
        @(posedge clk);

        HSEL = 1'b1;
        HTRANS = 2'b10;
        HADDR = addr;
        HWRITE = 1'b1;
        HWDATA = {32{1'bx}};
        HSIZE = 3'b010;

        @(posedge clk);

        HTRANS = 2'b00;
        HWDATA = data;

        repeat(4) begin
            @(posedge clk);
            if(HREADY_OUT) begin
                // $display("[%m]#%t INFO: Write Value: 0x%08x @ 0x%08x", $time, HWDATA, HADDR);
                HSEL = 1'b0;
                HADDR = 8'h0;
                HWRITE = 1'b0;
                HWDATA = {32{1'bx}};
                HSIZE = 3'b000;

                HTRANS = 2'b0;
                disable ahb_write;
            end
        end
        $stop;
    end
endtask

task print_memory;
    begin
        print_mem = 1;
        @(posedge clk);
        #(TCLK / 2);
        print_mem = 0;
    end
endtask

integer i;
integer value;

initial begin
    @(posedge rst_n);
    repeat(4) @(posedge clk);

    for(i = 0; i < 16; i = i + 4) begin
        ahb_read(i, value);
    end

    for(i = 0; i < 512; i = i + 4) begin
        ahb_write(32'h100 + i, 32'habcd_0000 + i);
    end

    repeat(4) @(posedge clk);
    print_memory();
    repeat(4) @(posedge clk);
    $stop;
end

ahb_mem dut(
            .clk(clk),
            .reset_n(rst_n),
            .sHADDR(HADDR),
            .sHWDATA(HWDATA),
            .sHWRITE(HWRITE),
            .sHREADYOUT(HREADY_OUT),
            .sHSIZE(HSIZE),
            .sHBURST(HBURST),
            .sHSEL(HSEL),
            .sHTRANS(HTRANS),
            .sHRDATA(HRDATA),
            .sHRESP(HRESP),
            .sHREADY(HREADY_IN),

            .print(print_mem)
        );

endmodule


